/*
 * CRtpSound.cpp
 *
 *  Created on: 2018年8月27日
 *      Author: zhengboyuan
 */

#include "CRtpSound.h"

#include "CRtpUnPacker.h"
#include "g711.h"
#include "CLog.h"


#ifdef ANDROID
#include "jni/NativeAudioDevice.h"
#else
#include "sdl/CAudioDevice.h"
#endif //


static av::AudioDevice* createAudioDevice()
{
#ifdef ANDROID
    return new av::NativeAudioDevice();
#else
    return new av::CAudioDevice();
#endif //
}



CRtpSound::CRtpSound():
        m_device(createAudioDevice()),
        m_codec(),
        m_rtpUnPacker(new av::CRtpUnPacker()),
        m_pts()
{
}

CRtpSound::~CRtpSound()
{
    close();
}

int CRtpSound::open(int port, int codec, int channels, int samplerate)
{
    CLog::info("CRtpSound::open. port: %d, codec: %d, channels: %d, rate: %d\n", port, codec, channels, samplerate);

    if (codec != av::MEDIA_CODEC_G711A && codec != av::MEDIA_CODEC_G711U)
    {
        return EINVAL;
    }

    if (channels <= 0 || samplerate <= 0)
    {
        return EINVAL;
    }

    if (!m_socket.open("", port))
    {
        CLog::warning("failed to setup socket. port: %d\n", port);
        return ENOENT;
    }

    m_codec = codec;

    m_device->open(channels, samplerate, 16);
    m_device->pause(false);

    if (!isRunning())
    {
        start();
    }

    return 0;
}

void CRtpSound::close()
{
    CLog::info("CRtpSound::close\n");

    if (isRunning())
    {
        stop();

        m_device->pause(true);
        m_socket.close();
    }
}

float CRtpSound::getVolume()
{
    return m_device->getVolume();
}

void CRtpSound::setVolume(float volume)
{
    m_device->setVolume(volume);
}

int CRtpSound::run()
{
    while (!m_canExit)
    {
        av::RtpPacketHandler handler = std::bind(&CRtpSound::handleRecvRtpPacket, this, std::placeholders::_1);

        m_socket.recv(handler, 1000 * 3);
    }

    return 0;
}

void CRtpSound::doStop()
{
    m_socket.abort();
}

void CRtpSound::handleRecvRtpPacket(av::RtpPacket& packet)
{
    av::MediaPacket pktOut;
    if (m_rtpUnPacker->unpack(packet, pktOut))
    {
        onRecvPacket(pktOut);
    }
}

void CRtpSound::onRecvPacket(av::MediaPacket& pkt)
{
    m_buffer.ensure(pkt.size * 2);
    uint16_t* data = (uint16_t*)m_buffer.data();

    if (m_codec == av::MEDIA_CODEC_G711A)
    {
        for (int i = 0; i < pkt.size; i ++)
        {
            data[i] = alaw2linear(pkt.data[i]);
        }
    }
    else
    {
        for (int i = 0; i < pkt.size; i ++)
        {
            data[i] = ulaw2linear(pkt.data[i]);
        }
    }

    m_device->write(m_buffer.data(), pkt.size * 2, pkt.pts);

    m_pts += pkt.size * 2;
}

